package com.dp.server.entities;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;


import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.apache.regexp.RE;
import org.h2.table.Plan;
import org.hibernate.annotations.GenericGenerator;


import com.dp.client.dto.Fecha;
import com.dp.client.dto.PlanDeVueloDTO;
import com.dp.server.MantenimientoGenerico;
import com.google.gwt.i18n.client.DateTimeFormat;

@Entity
public class PlanDeVuelo {
	private int id;
	static int hours_to_ms =  60 * 60 * 1000;
	static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private int idPaquete;
	private boolean eliminado;
	private int[] reservas;
	private int[] idEstancia;
	private int indiceActualReserva;

	public Paquete actualizarPaquete(){
		MantenimientoGenerico< Paquete > mPaquete = new MantenimientoGenerico<>("Paquete");
		Paquete p = mPaquete.buscarID( idPaquete );
		if( enAlmacen() ) p.setAlmacenActual( obtenerIdActual() );
		else			  p.setVueloActual( obtenerIdActual() );
		return p;
	}
	
	public void setIdEstancia(int[] idEstancia) {
		this.idEstancia = idEstancia;
	}

	public int[] getIdEstancia() {
		return idEstancia;
	}

	public int getIdPaquete() {
		return idPaquete;
	}

	public void setIdPaquete(int idPaquete) {
		this.idPaquete = idPaquete;
	}

	public int[] getReservas() {
		return reservas;
	}

	public void setReservas(int[] reservas) {
		this.reservas = reservas;
	}

	public int getIndiceActualReserva() {
		return indiceActualReserva;
	}

	public void setIndiceActualReserva(int indiceActualReserva) {
		this.indiceActualReserva = indiceActualReserva;
	}

	public int obtenerIdActual() {
		return idEstancia[indiceActualReserva];
	}

	boolean enAlmacen() {
		return (indiceActualReserva % 2) == 0;
	}

	boolean estadoFinal() {
		return indiceActualReserva >= reservas.length - 1;
	}
	/*
	 * Avanza en la posicion de un paquete y devuelve el paquete actualizado listo para ser comiteado
	 */
	public Paquete avanzar() {
		if (estadoFinal())
			return null;
		indiceActualReserva++;
		return actualizarPaquete();
	}
	/*
	 * Retrocede en la posicion de un paquete y devuelve el paquete actualizado listo para ser comiteado
	 */
	public Paquete retroceder() {
		if (indiceActualReserva == 0)
			return null;
		indiceActualReserva--;
		return actualizarPaquete();
	}

	public boolean isEliminado() {
		return eliminado;
	}

	public void setEliminado(boolean eliminado) {
		this.eliminado = eliminado;
	}
	public int [] devolverIdVuelos(){
		int [] vuelos = new int [ idEstancia.length / 2 ];
		for( int i = 1 ; i < idEstancia.length ; i+=2 ){
			vuelos[ i / 2 ] = idEstancia[ i ];
		}
		return vuelos;
	}
	@Id
	@GeneratedValue(generator = "increment")
	@GenericGenerator(name = "increment", strategy = "increment")
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public PlanDeVuelo() {
	}

	static public PlanDeVuelo createPlan(Paquete paq, int[] idVuelo) {
		if(idVuelo.length == 0){
			PlanDeVuelo ans = new PlanDeVuelo();
			MantenimientoGenerico<Vuelo> mVuelo = new MantenimientoGenerico<>("Vuelo");
			MantenimientoGenerico<PlanDeVuelo> mPlanDeVuelo = new MantenimientoGenerico<>("PlanDeVuelo");
			ans = mPlanDeVuelo.registra( ans );
			ans.setEliminado(false);
	 		ans.setIdEstancia(new int[0]  );
	 		ans.setIndiceActualReserva( 0 );
	 		ans.setIdPaquete( paq.getId() );
	 		ans.setReservas( new int[0] );
	 		ans = mPlanDeVuelo.modifica( ans );
	 		return ans;
		}
		try {
			PlanDeVuelo ans = new PlanDeVuelo();
			MantenimientoGenerico<Vuelo> mVuelo = new MantenimientoGenerico<>("Vuelo");
			MantenimientoGenerico<PlanDeVuelo> mPlanDeVuelo = new MantenimientoGenerico<>("PlanDeVuelo");
			ans = mPlanDeVuelo.registra( ans );
			Vuelo inicio = mVuelo.buscarID( idVuelo[ 0 ] );
			Date fechaInicio = paq.getFechaRegistro(), fechaFin = inicio.getFechaHoraSalida()	;
			int n = idVuelo.length;
			int [] idEst = new int[ 2 * n + 1 ];
			int [] idRes = new int[ 2 * n + 1 ];
			Vuelo [] vuelos = new Vuelo [ idVuelo.length ];
			for( int i = 0 ; i < n ; i++ ) vuelos[ i ] = mVuelo.buscarID( idVuelo[ i ] );
			idEst[ 0 ] = inicio.getIdOrigen();
			idRes[ 0 ] = ReservaAlmacen.createReserva( paq , fechaInicio, fechaFin , ans , inicio.getIdOrigen() ).getId(); 
			// crear reserva y darle el id de el 1er almacen;
	 		
			fechaInicio = fechaFin;
			Calendar calendar = Calendar.getInstance();
			for( int i = 0 , j = 1 ; i < idVuelo.length ; i++ , j +=2 ){
				inicio = vuelos[ i ];
				idEst[ j ] = idVuelo[ i ];
	 			idEst[ j + 1 ] = inicio.getIdDestino();
	 			// crear reserva para el vuelo y reserva para el Almacen
	 			idRes[ j ] = ReservaVuelo.createReserva( paq , ans , inicio ).getId();
	 			calendar.setTime( vuelos[ i ].getFechaHoraSalida() );
	 			//fechaInicio = new Date( vuelos[ i ].getFechaHoraSalida().getTime() + vuelos[ i ].getDuracion() * hours_to_ms ) ;
	 			calendar.add( Calendar.HOUR_OF_DAY , vuelos[ i ].getDuracion() );
	 			fechaInicio = calendar.getTime();
	 			calendar.setTime(fechaInicio);
	 			calendar.add( Calendar.HOUR_OF_DAY, 1 );
	 			fechaFin = i + 1 == idVuelo.length ? 
	 								calendar.getTime()
	 								: vuelos[ i + 1 ].getFechaHoraSalida();
	 			idRes[ j + 1 ] = ReservaAlmacen.createReserva(paq, fechaInicio, fechaFin, ans , inicio.getIdDestino() ).getId();
			}
	 		ans.setEliminado(false);
	 		ans.setIdEstancia( idEst );
	 		ans.setIndiceActualReserva( 0 );
	 		ans.setIdPaquete( paq.getId() );
	 		ans.setReservas( idRes );
	 		ans = mPlanDeVuelo.modifica( ans );
			return ans;
		} catch ( Exception e ){
			System.out.println( e.getMessage() );
			return null;
		}
	}
	/*
	 * ir Avanzando en la lista de cosos de plan de vuelo eliminando los recursos seteados a cada avion , almacen 
	 * ya que se supone que este plan ya no es valido
	 * */
	public void liberarRutaRestante() {
		MantenimientoGenerico<ReservaAlmacen> reserva = new MantenimientoGenerico<ReservaAlmacen>("ReservaAlmacen");
		MantenimientoGenerico<ReservaVuelo> vuelo = new MantenimientoGenerico<ReservaVuelo>("ReservaVuelo");
		for( indiceActualReserva+= ( enAlmacen() ? 1 : 0 ) ; indiceActualReserva < reservas.length ; indiceActualReserva++ ){
			if( enAlmacen() ){
				reserva.eliminar(reservas[ indiceActualReserva ]);
			} else {
				vuelo.eliminar(reservas[ indiceActualReserva ]);
			}
		}
	}
	
	public static PlanDeVuelo tomaCascara( int [] idVuelo ){
		PlanDeVuelo plan = new PlanDeVuelo();
		plan.indiceActualReserva = 1 << 20;
		MantenimientoGenerico<Vuelo> mVuelo = new MantenimientoGenerico<Vuelo>("Vuelo");
		Vuelo[] vuelos = new Vuelo[ idVuelo.length ];
		for( int i = 0 ; i < idVuelo.length ; i++ ) vuelos[ i ] = mVuelo.buscarID( idVuelo[ i ] );
		plan.idEstancia[ 0 ] = vuelos[ 0 ].getIdOrigen();
		for( int i = 0 , j = 1 ; i < idVuelo.length ; i++ , j+=2 ){
			plan.idEstancia[ j ] = vuelos[ i ].getId();
			plan.idEstancia[ j + 1 ] = vuelos[ i ].getIdDestino();
		}
		return plan;
	}
	
	public PlanDeVueloDTO extractDTO(){
		PlanDeVueloDTO ans = new PlanDeVueloDTO();
		List<String> hora_salida = new ArrayList<>();
		List<String> hora_llegada = new ArrayList<>();
		List<String> vuelo = new ArrayList<>();
		List<String> almacen = new ArrayList<>();
		List<String> inicioAlmacen = new ArrayList<>();
		List<String> finAlmacen = new ArrayList<>();
		MantenimientoGenerico<ReservaAlmacen> mRAlmacen = new MantenimientoGenerico<>("ReservaAlmacen");
		MantenimientoGenerico<Almacen> mAlmacen = new MantenimientoGenerico<>("Almacen");
		MantenimientoGenerico<Vuelo> mVuelo = new MantenimientoGenerico<>("Vuelo");
		ReservaAlmacen [] rAlmacen = new ReservaAlmacen[ ( reservas.length + 1 ) / 2 ];
		Almacen [] Palmacen = new Almacen [ rAlmacen.length ];
		Vuelo [] Pvuelo = new Vuelo [ rAlmacen.length - 1  ];
		for( int i = 0 ; i < rAlmacen.length ; i++ )	
			rAlmacen[ i ] = mRAlmacen.buscarID( reservas[ i * 2 ] );
		for( int i =0 ; i < rAlmacen.length ; i++ )
			Palmacen[ i ] = mAlmacen.buscarID( idEstancia[ i * 2 ] );
		for( int i = 0 ; i < Pvuelo.length ; i++ )
			Pvuelo[ i ] = mVuelo.buscarID( idEstancia[ i * 2 + 1 ] );
		for( Vuelo v : Pvuelo ) hora_salida.add( format.format( v.getFechaHoraSalida() ) );
		for( Vuelo v : Pvuelo ) hora_llegada.add( format.format( v.getFechaHoraLLegada() ) );
		for( int i = 0 ; i < Pvuelo.length ; i++ ){
			Vuelo v = Pvuelo[ i ];
			vuelo.add( v.getId() + ":" + Palmacen[ i ].getDescripcion() + " > " + Palmacen[ i + 1 ].getDescripcion() ) ;
		}
		for( Almacen a : Palmacen ) almacen.add( a.getId() + ":" + a.getDescripcion() );
		for( ReservaAlmacen ra : rAlmacen )inicioAlmacen.add( format.format(ra.getFechaInicio() ) );
		for( ReservaAlmacen ra : rAlmacen )finAlmacen.add( format.format(ra.getFechaFin() ) );

		ans.idEstancia = idEstancia;
		ans.posicionActual = indiceActualReserva;
		ans.hora_salida = hora_salida;
		ans.hora_llegada = hora_llegada;
		ans.vuelo = vuelo;
		ans.almacen = almacen;
		ans.inicioAlmacen = inicioAlmacen;
		ans.finAlmacen = finAlmacen;
		return ans;
	}
	
	public void recoger(){
		indiceActualReserva = idEstancia.length + 1;
	}
}
